package org.dreamwork.cai.proxy;

import org.dreamwork.cai.io.IRemoteServiceStub;
import org.dreamwork.cai.core.RemoteServiceFactory;
import org.dreamwork.cai.srf.MethodInfo;
import org.dreamwork.cai.srf.ServiceRouteItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class RemoteProxyHandler implements InvocationHandler {
    private final Logger logger = LoggerFactory.getLogger (RemoteProxyHandler.class);

    private final ServiceRouteItem sri;

    private RemoteProxyHandler (ServiceRouteItem sri) {
        this.sri = sri;
    }

    // service.doSomething ();
    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getDeclaringClass () == Object.class) {
            return method.invoke (proxy, args);
        }

        if (logger.isTraceEnabled ()) {
            logger.trace ("invoking on proxy handler : {");
            logger.trace ("    method    : {}", method);
            logger.trace ("    generic   : {}", method.toGenericString ());
            logger.trace ("    SRI       : {}", sri);
            logger.trace ("    args      : {}", args);
            if (args != null && args.length > 0) {
                logger.trace ("    parameters: {");
                for (int i = 0; i < args.length; i ++) {
                    logger.trace ("        [{}] - {}", i, args [i]);
                }
                logger.trace ("    }");
            }
            logger.trace ("}");
            logger.trace ("invoking method {} on SRI {}, with parameters: {}", method, sri, Arrays.toString (args));
        }

        MethodInfo mi = sri.find (method);
        if (mi != null) {
            IRemoteServiceStub service = RemoteServiceFactory.getRemoteService ();
            return service.invoke (sri, mi, args);
        }
        return null;
    }

    @Override
    public String toString () {
        return RemoteProxyHandler.class.getCanonicalName ();
    }

    public static Object create (ServiceRouteItem sri, Class<?>... interfaces) {
        if (sri == null || interfaces.length == 0) {
            return null;
        }
        RemoteProxyHandler handler = new RemoteProxyHandler (sri);
        return Proxy.newProxyInstance (RemoteProxyHandler.class.getClassLoader (), interfaces, handler);
    }
}